﻿Shader "Custom/FlagCharacter"
{
    Properties
    {
        [HDR]_BaseColor("BaseColor",Color) = (1,1,1,1)
        _LightIntensity("LightIntensity",float) = 1
        _BaseMap ("BaseMap", 2D) = "white" {}
        _TexArray ("TexArray", 2DArray) = "white" {}
        _TexIndex ("Tex Index", Float) = 0
        _FlagSize ("FlagSize", Vector) = (128.0, 383.0, 512.0, 512.0)
        _Mask("Mask", 2D) = "white" {}
        _CampColorIntensity("Camp Color Intensity", Range( 0 , 10)) = 3
        [HDR]_CampColor("Camp Color", Color) = (1,1,1,1)
        _FlagColorIntensity("Flag Color Intensity", Range( 0 , 10)) = 3
        [HDR]_FlagColor("Flag Color", Color) = (1,1,1,1)
        [Enum(Off,1,On,0)] _ShowFlag ("Show Flag", Float) = 0
        [Header(Specular)]
        [HDR]_SpecColor("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
        _SpecIntensity("Specular Intensity",float) = 1
        _Smoothness("Smoothness", Range(0,1)) = 0.5
        [HideInInspector]_Alpha("Alpha",float) = 1
    }
    SubShader
    {
        Tags
        {
            "RenderType" = "Transparent" "Queue" = "Transparent" "RenderPipeline" = "UniversalPipeline"
        }
        LOD 100
        Blend SrcAlpha OneMinusSrcAlpha
        Pass
        {
            Tags
            {
                "LightMode" = "UniversalForward"
            }
            Cull Off
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 4.5
            #pragma multi_compile _ DOTS_INSTANCING_ON

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float2 uv1 : TEXCOORD1;
                float2 uv2 : TEXCOORD2;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float3 normalWS : TEXCOORD1;
                float4 positionCS : SV_POSITION;
                float3 positionWS : TEXCOORD2;
                float3 viewDirWS : TEXCOORD3;
            };

            TEXTURE2D(_Mask);
            SAMPLER(sampler_Mask);
            
            CBUFFER_START(UnityPerMaterial)
            
            sampler2D _BaseMap;
            float4 _BaseMap_ST;
            float4 _FlagSize;
            float4 _CampColor;
            float4 _Mask_ST;
            float4 _FlagColor;
            float _ShowFlag;
            float _CampColorIntensity;
            float _FlagColorIntensity;

            TEXTURE2D_ARRAY(_TexArray);
            SAMPLER(sampler_TexArray);

            float _TexIndex;

            half4 _BaseColor;
            float _LightIntensity;
            float4 _SpecColor;
            float _SpecIntensity;
            float _Smoothness;
            float _Alpha;
            
            CBUFFER_END

            // main_color 是原始采样出的反射贴图颜色
            float4 get_flag_tex(const float4 flag_size, const float4 main_color, const float2 uv)
            {
                const float flag_w = flag_size.x / flag_size.z;
                const float flag_h = flag_size.y / flag_size.w;
                if (uv.x > flag_w || uv.y > flag_h) return main_color; // 非 Flag 区域返回原始颜色
                const float x_rate = uv.x / flag_w; // 将主贴图的UV转换到旗帜贴图的UV
                const float y_rate = uv.y / flag_h; // 将主贴图的UV转换到旗帜贴图的UV
                const float2 target = float2(x_rate, y_rate);
                int offset = _TexIndex; // 使用的哪个索引
                return SAMPLE_TEXTURE2D_ARRAY(_TexArray, sampler_TexArray, target, offset);
            }

            v2f vert(appdata v)
            {
                v2f o;
                o.uv = v.uv;
                float4 pos = v.vertex;
                o.normalWS = TransformObjectToWorldNormal(v.normal);
                o.positionWS = TransformObjectToWorld(pos.xyz);
                o.viewDirWS = GetWorldSpaceViewDir(o.positionWS);
                o.positionCS = TransformObjectToHClip(pos.xyz);
                return o;
            }

            half4 frag(v2f i) : SV_Target
            {
                half4 baseColor = tex2D(_BaseMap, i.uv) * _BaseColor;
                baseColor = get_flag_tex(_FlagSize, baseColor, i.uv); // 这一步已经得到了渲染好旗帜后的颜色
                
                float2 uv_Mask = i.uv.xy * _Mask_ST.xy + _Mask_ST.zw; // 计算出Mask贴图的uv
                float4 mask = SAMPLE_TEXTURE2D(_Mask, sampler_Mask, uv_Mask); // 采样出Mask的值
                float4 campCol = lerp(baseColor, (baseColor * _CampColor * _CampColorIntensity), mask.r); // mask的r通道控制角色身上需要改色的区域
                float4 flagCol = lerp(campCol, (baseColor * _FlagColor * _FlagColorIntensity), mask.g); // mask的g通道控制旗帜区域的修改颜色
                
                float use_flag = _ShowFlag;
                use_flag = step(1, use_flag);
                clip(mask.a - 0.7 * use_flag); // mask的a通道控制旗帜是否显示，传入负数时丢弃像素，则不会显示
                
                float3 diffuseColor = lerp(flagCol.rgb, campCol.rgb, use_flag);
                float3 normalWS = normalize(i.normalWS);
                diffuseColor = diffuseColor * _LightIntensity;
                float smoothness = exp2(10 * _Smoothness + 1);

                float3 halfVec = SafeNormalize(float3(i.viewDirWS) + float3(i.viewDirWS));
                half NdotH = saturate(dot(normalWS, halfVec));
                half modifier = pow(NdotH, smoothness);
                half3 specularColor = _SpecColor.rgb * modifier * _SpecIntensity * _LightIntensity;

                half3 finalColor = diffuseColor.rgb + specularColor * mask.b; // mask的b通道控制高光反射，即角色身上的盔甲等会反射的部分

                return half4(finalColor, _Alpha);
            }
            ENDHLSL
        }

        Pass
        {
            Name "ShadowCaster"
            Tags
            {
                "LightMode" = "ShadowCaster"
            }
            Cull Off
            HLSLPROGRAM
            #pragma vertex vert_shadow
            #pragma fragment frag_shadow
            #pragma multi_compile_shadowcaster
            #pragma target 4.5

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            float3 _LightDirection;

            struct appdata_shadow
            {
                float4 positionOS : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
                float2 uv1 : TEXCOORD1;
                float2 uv2 : TEXCOORD2;
            };

            struct Varyings
            {
                float2 uv : TEXCOORD0;
                float4 positionCS : SV_POSITION;
            };

            TEXTURE2D(_Mask);
            SAMPLER(sampler_Mask);
            
            CBUFFER_START(UnityPerMaterial)
            
            sampler2D _BaseMap;
            float4 _BaseMap_ST;
            float4 _FlagSize;
            float4 _CampColor;
            float4 _Mask_ST;
            float4 _FlagColor;
            float _CampColorIntensity;
            float _FlagColorIntensity;

            half4 _BaseColor;
            float _LightIntensity;
            float4 _SpecColor;
            float _SpecIntensity;
            float _Smoothness;
            float _Alpha;
            
            CBUFFER_END

            Varyings vert_shadow(appdata_shadow v)
            {
                Varyings output;
                float4 pos = v.positionOS;
                float4 normal = float4(v.normal, 0);
                float3 positionWS = TransformObjectToWorld(pos.xyz);
                float3 normalWS = TransformObjectToWorldNormal(normal.xyz);
                output.positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, _LightDirection));
                output.uv = TRANSFORM_TEX(v.uv, _BaseMap);

                #if UNITY_REVERSED_Z
                    output.positionCS.z = min(output.positionCS.z, output.positionCS.w * UNITY_NEAR_CLIP_VALUE);
                #else
                    output.positionCS.z = max(output.positionCS.z, output.positionCS.w * UNITY_NEAR_CLIP_VALUE);
                #endif
                
                return output;
            }

            half4 frag_shadow(Varyings input) : SV_TARGET
            {
                float4 mask = SAMPLE_TEXTURE2D(_Mask, sampler_Mask, input.uv);
                clip(mask.a - 0.5);
                return 0;
            }
            ENDHLSL
        }
    }
}
